﻿/************************************************************************
 * SMLib - State Model Library
 * Copyright (C) 2012-2013 Ali Khalili (khalili_DOT_ir_@SIGN_gmail_DOT_com)
 * **********************************************************************
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License (LGPL) published 
 * by the Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version. This program is distributed without any
 * warranty. See the GNU Lesser General Public License for more details. 
 * ***********************************************************************
 * File         :     SMLib\Utils\Utils.cs
 * Description  :     A set of utility class
 * Change log   :     -2011: initial version (oroginally for SimGine library)
 * To Do        :
 ************************************************************************/
using System;
using System.Collections.Generic;
using System.Collections;

namespace SMLib.Utils
{
    /// <summary>
    /// Some function utility for sorting/ordering numbers
    /// </summary>
    internal class SortUtil
    {
        /// <summary>
        ///  Find the N minimum (distinct) number of a list
        ///  Note: it is not optimal solution!
        /// </summary>
        /// <param name="N">number of minimum nubers to be found</param>
        /// <param name="theList">the whole list</param>
        /// <returns>the list of minimum numbers</returns>
        public static List<int> Find(int N, List<int> theList)
        {
            List<int> minList = new List<int>();
            int numberOfFound = 0;

            minList = new List<int>();
            for (int i = 0; i < theList.Count; i++)
            {
                if (numberOfFound < N)
                {
                    if (numberOfFound == 0)
                    {
                        minList.Add(theList[i]);
                        numberOfFound++;
                        continue;
                    }
                    // Add to the end
                    else if (minList[numberOfFound - 1] < theList[i])
                    {
                        minList.Add(theList[i]);
                        numberOfFound++;
                        continue;
                    }

                    int k;
                    for (k = 0; k < numberOfFound; k++)
                    {
                        if (theList[i] < minList[k])
                        {
                            minList.Insert(k, theList[i]);
                            numberOfFound++;
                            break;
                        }
                        // It already has this number
                        else if (minList[k] == theList[i])
                            break;
                    }
                }
                else
                {
                    if (!(theList[i] > minList[N - 1]))
                    {
                        // We have to insert it in to the list
                        int k;
                        for (k = 0; k < N; k++)
                        {
                            // Insert it here
                            if (theList[i] < minList[k])
                            {
                                minList.Insert(k, theList[i]);
                                minList.RemoveAt(N);
                                break;
                            }
                            // It already has this number
                            else if (minList[k] == theList[i])
                                break;
                        }
                    }
                }
            }
            return minList;
        }
    }


    /// <summary>
    /// A list with additional value
    /// </summary>
    /// <typeparam name="T">type of list</typeparam>
    /// <typeparam name="VALUETYPE">type of additional value</typeparam>
    internal class ValuedList<T, VALUETYPE>
        : List<T>
    {
        public VALUETYPE value;

        public ValuedList(VALUETYPE value)
        {
            this.value = value;
        }

        public ValuedList()
        {
            /// nothing!
        }

        /// <summary>
        /// Here, we don't care about the value (it should be used by application). We just make two of them union
        /// </summary>
        /// <param name="lst"></param>
        public void Union(ValuedList<T, VALUETYPE> lst)
        {
            foreach (T t in lst)
            {
                /// we should use "equal" function, becuase we may want to add two node that has 
                /// equal ID but they belong two different machine!!!!!!!!
                //bool existsInList = false;
                //foreach (T tt in this)
                //{
                //    if ((T)tt == (T)t)
                //    {
                //        existsInList = true;
                //        break;
                //    }
                //}
                //if (!Contains(t))
                Add(t);
            }
        }
    }

    /// <summary>
    /// [To Do: Remove: Use ValuedList'bool instead]
    /// A list which contains a boolean flag!
    /// </summary>
    /// <typeparam name="T">type of elements of the list</typeparam>
    internal class FlaggedList<T> : List<T>
    {
        public bool flag = true;

        public void Union(FlaggedList<T> lst)
        {
            foreach (T t in lst)
                //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                if (!Contains(t))
                    Add(t);
        }
    }



    //static Word 	concat(Word myAccessString, ISymbol input)
    //          returns a copy of the original Word with one ISymbol attached
    //static Word 	concat(Word myAccessString, ISymbol s1, ISymbol s2)
    //          retuerns a copy of the original Word with two Symbols attached
    //static Word 	concat(Word myAccessString, Word w2)
    //          concatenates two words AND returns a corresponding NEW word
    //static Word 	flattenTrace(Word trace)
    //          Fold "virtual" letters (splitters) back to the normal alphabet
    //static boolean 	isPrefixOf(Word myAccessString, Word w2)
    //          Checks if the first given Word is a prefix of the second given Word
    //static ISymbol 	lastSymbol(Word w)
    //static Word 	prefix(Word myAccessString, int length)
    //static Word 	suffix(Word myAccessString, int length)
    //static Word 	toWord(ISymbol input)
    //          cast symbol to word
    //static ISymbol 	turnWordIntoSymbol(Word w)
    //          Turn word into a symbol, which has a list of the symbols of the input word as user object

    /// <summary>
    /// Some utility functions for working with Lists
    /// </summary>
    internal class ListUtil
    {
        /// <summary>
        /// [Instead of List, we may use EnList which has "Equals"]
        /// Determine that two lists are equal or not
        /// </summary>
        /// <param name="l1"></param>
        /// <param name="l2"></param>
        /// <returns></returns>
        public static bool EqualLists(IList l1, IList l2)
        {
            if (l1.Count != l2.Count)
                return false;
            for (int i = 0; i < l1.Count; i++)
                if (!l1[i].Equals(l2[i]))
                    return false;
            return true;
        }

        /// <summary>
        /// Write the content of a list in console
        /// </summary>
        /// <param name="l1"></param>
        /// <param name="separator"></param>
        public static void WriteList(IList l1, string separator = ",")
        {
            if (l1 == null) { Console.Write("TestResultType: Null list!"); return; }
            for (int i = 0; i < l1.Count; i++)
                Console.Write((i > 0 ? separator : "") + l1[i].ToString());
        }

        /// <summary>
        /// Conver a list to string
        /// </summary>
        /// <param name="l1">the list</param>
        /// <param name="separator">separator between elements</param>
        /// <returns>the generated string</returns>
        public static string ListToString(IList l1, string separator = ",")
        {
            string temp = "";
            if (l1 == null) { return "<>"; }
            for (int i = 0; i < l1.Count; i++)
                temp += ((i > 0 ? separator : "") + (l1[i] == null ? "NULL" : l1[i].ToString()));
            return temp;
        }


        /// <summary>
        /// The maximum index till which two lists are equal
        /// </summary>
        /// <param name="l1">first list</param>
        /// <param name="l2">second list</param>
        /// <returns></returns>
        public static int PrefixLength(IList l1, IList l2)
        {
            int min = Math.Min(l1.Count, l2.Count);
            for (int i = 0; i < min; i++)
            {
                if (!l1[i].Equals(l2[i]))
                    return i;
            }
            return min;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="l"></param>
        /// <param name="len"></param>
        /// <returns></returns>
        public static List<T> Prefix<T>(List<T> l, int len)
        {
            List<T> p = new List<T>();
            for (int i = 0; i < len; i++)
                p.Add(l[i]);
            return p;
        }

        /// <summary>
        /// Suffix of a list 
        /// </summary>
        /// <typeparam name="T">type of list</typeparam>
        /// <param name="l">the list</param>
        /// <param name="len">length of suffix</param>
        /// <returns>the extracted suffix</returns>
        public static List<T> Suffix<T>(List<T> l, int len)
        {
            List<T> p = new List<T>();
            for (int i = l.Count - len; i < l.Count; i++)
                p.Add(l[i]);
            return p;
        }
        
        /*
        public static int SuffixLength(IList l1, IList l2)
        {
            int min = Math.Min(l1.Count, l2.Count);
            for (int i = 0; i < min; i++)
            {
                if (!l1[i].Equals(l2[i]))
                    return i;
            }
            return min;
        }
        */
    }

}
